package org.cjlm.ui;

import org.cjlm.config.AppConfig;
import org.cjlm.config.ConfigLoader;
import org.cjlm.config.FrameConfig;
import org.cjlm.config.MenuActionConfig;
import org.cjlm.config.MenuConfig;
import org.cjlm.ui.pub.MAbstraction;
import org.cjlm.ui.pub.MInternalFrame;
import org.cjlm.ui.pub.MMenu;

import javax.swing.*;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BoxMain extends JFrame {
    private JDesktopPane desktop = new JDesktopPane();

    private Map<String, MInternalFrame> frameRegistry = new HashMap<>();

    private AppConfig config;

    private Connection conn;

    public BoxMain() throws Exception {
        // 加载配置文件
        try{
            config = ConfigLoader.loadMainConfig("BoxMain");

            setTitle(config.getTitle());
            setSize(config.getWidth(),  config.getHeight());
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            // 初始化功能区
            initMenuBar();
            add(desktop);
        }catch (Exception e){
            // 显示详细错误对话框并退出程序
            handleConfigLoadError(e);
            throw e;
        }
    }
    
    private void initMenuBar() throws Exception {
        JMenuBar menuBar = new JMenuBar();
        Map<String, MMenu> menuMap = new HashMap<>();

        List<MenuConfig> allMenuList = new ArrayList<>();
        allMenuList.addAll(config.getMenu());
        allMenuList.addAll(config.getFrame());
        allMenuList.addAll(config.getMenuActions());

        allMenuList.sort(Comparator
                .comparing((MenuConfig menu) -> menu.getParent()  != null, Comparator.naturalOrder())
                .thenComparing(MenuConfig::getParent, Comparator.nullsLast(String::compareTo))
                .thenComparing(MenuConfig::getCode, Comparator.nullsLast(String::compareTo))
        );

        for (var menuCfg : allMenuList)  {
            if(menuCfg instanceof FrameConfig){
                var frameCfg = (FrameConfig)menuCfg;
                MMenu parentMenu = menuMap.get(frameCfg.getParent());
                if (parentMenu != null) {
                    parentMenu.add(createLaunchItem(
                            frameCfg.getName(),
                            frameCfg.getClassName(),
                            frameCfg.isMultiInstance(),
                            frameCfg.isMaximized(),
                            frameCfg.getWidth(),
                            frameCfg.getHeight()
                    ));
                }
            }else if(menuCfg instanceof MenuActionConfig){
                var actionCfg = (MenuActionConfig)menuCfg;
                MMenu parentMenu = menuMap.get(actionCfg.getParent());
                if (parentMenu != null) {
                    parentMenu.add(createActionItem(
                            actionCfg.getName(),
                            actionCfg.getClassName()
                    ));
                }
            }else{
                MMenu menu = new MMenu(menuCfg.getCode(),  menuCfg.getName());
                if(menuCfg.getParent() != null && menuCfg.getParent().trim().length() > 0){
                    MMenu parentMenu = menuMap.get(menuCfg.getParent());
                    parentMenu.add(menu);
                }else{
                    menuBar.add(menu);
                }
                menuMap.put(menuCfg.getCode(),  menu);
            }
        }

        setJMenuBar(menuBar);
    }

    private JMenuItem createLaunchItem(String title, String frameClassName, boolean isMul, boolean isMax, int width, int height) throws Exception {
        JMenuItem mu = new JMenuItem(title);
        mu.addActionListener(e  -> {
            try {
                if (!isMul && frameRegistry.containsKey(frameClassName))  {
                    MInternalFrame existing = frameRegistry.get(frameClassName);
                    existing.setVisible(true);
                    existing.toFront();
                    return;
                }

                // 新增位置计算逻辑
                int offset = 30 * desktop.getAllFrames().length;
                Point location = new Point(offset, offset);
                // 每次点击创建新实例
                MInternalFrame frame = (MInternalFrame) Class.forName(frameClassName)
                        .getConstructor(String.class, boolean.class,  int.class,  int.class)
                        .newInstance(title, isMax, width, height);

                frame.setLocation(location);  // 设置位置
                frame.setFrameRegistry(this.frameRegistry);
                frame.setDesktop(this.desktop);
                frame.setBoxMain(this);
                desktop.add(frame);

                frameRegistry.put(frameClassName,  frame);
                // 添加关闭监听自动清理
                frame.addInternalFrameListener(new  InternalFrameAdapter() {
                    @Override
                    public void internalFrameClosed(InternalFrameEvent e) {
                        frameRegistry.remove(frameClassName);
                    }
                });
                frame.setVisible(true);
            } catch (InvocationTargetException ex){
                JOptionPane.showMessageDialog(BoxMain.this,  "创建窗口失败: " + ex.getTargetException().getMessage());
                ex.getTargetException().printStackTrace();
            }catch (Exception ex) {
                JOptionPane.showMessageDialog(BoxMain.this,  "创建窗口失败: " + ex.getMessage());
                ex.printStackTrace();
            }
        });
        return mu;
    }

    private MAbstraction createActionItem(String title, String actionClassName) throws Exception {
        MAbstraction ma = (MAbstraction) Class.forName(actionClassName).getConstructor(String.class).newInstance(title);
        ma.setDesktop(this.desktop);
        ma.setFrameRegistry(this.frameRegistry);
        ma.setBoxMain(this);
        return ma;
    }

    /**
     * 处理配置文件加载失败的专业错误处理方法
     * @param exception 加载过程中抛出的异常
     */
    private void handleConfigLoadError(Exception exception) {
        // 构建详细错误信息
        String errorTitle = "系统初始化失败";
        StringBuilder errorMsg = new StringBuilder();

        errorMsg.append("<html><body  style='width: 400px; padding:10px'>");
        errorMsg.append("<h2  style='color:#c00;'>无法加载应用程序配置!</h2>");
        errorMsg.append("<p><b> 原因:</b> ").append(getRootCause(exception)).append("</p>");
        errorMsg.append("<p><b> 配置文件路径:</b> config/BoxMain.json</p>");
        errorMsg.append("<p><b> 解决方案:</b></p>");
        errorMsg.append("<ul>");
        errorMsg.append("<li> 确认配置文件存在于指定目录</li>");
        errorMsg.append("<li> 检查配置文件JSON格式是否正确</li>");
        errorMsg.append("<li> 验证配置文件访问权限</li>");
        errorMsg.append("<li> 查看日志文件获取详细信息</li>");
        errorMsg.append("</ul>");
        errorMsg.append("<p><b> 技术细节:</b><br/>").append(exception.toString()).append("</p>");
        errorMsg.append("</body></html>");

        // 创建专业错误对话框
        JOptionPane.showMessageDialog(
                null, // 无父组件
                errorMsg.toString(),
                errorTitle,
                JOptionPane.ERROR_MESSAGE
        );
    }

    /**
     * 获取异常的根本原因
     * @param e 原始异常
     * @return 根本原因描述
     */
    private String getRootCause(Throwable e) {
        Throwable root = e;
        while (root.getCause()  != null && root.getCause()  != root) {
            root = root.getCause();
        }
        StringBuilder cause = new StringBuilder();
        cause.append(root.getClass().getSimpleName()).append(":  ").append(root.getMessage());

        // 添加路径相关错误特殊提示
        if (root.getMessage()  != null && root.getMessage().contains("config/"))  {
            cause.append("  [路径相关错误]");
        }
        return cause.toString();
    }
}